/*
 * Copyright (C) 2021 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.bytedance.scene;

import ohos.aafwk.ability.Ability;
import ohos.agp.colors.RgbColor;
import ohos.agp.colors.RgbPalette;
import ohos.agp.components.Component;
import ohos.agp.components.ComponentContainer;
import ohos.agp.components.DirectionalLayout;
import ohos.agp.components.element.ShapeElement;
import ohos.agp.utils.Color;
import ohos.agp.window.service.WindowManager;
import ohos.app.Context;

import java.lang.reflect.Field;

import static ohos.agp.colors.RgbColor.fromArgbInt;
import static ohos.agp.components.Component.HIDE;
import static ohos.agp.components.Component.VISIBLE;
import static ohos.agp.window.service.WindowManager.LayoutConfig.MARK_TRANSLUCENT_STATUS;

/**
 * 沉浸式状态栏
 *
 * @since 2021-06-16
 */
public class StatusBarUtil {
    private static final String DEFAULT_STATUS_BAR_COLOR = "#146e6e";
    private static final int DEFAULT_STATUS_BAR_HIGHT = 129;
    private static final int DEFAULT_STATUS_BAR_ALPHA = 112;
    private static final int FAKE_STATUS_BAR_VIEW_ID = 2131558418;
    private static final int FAKE_TRANSLUCENT_VIEW_ID = 2131558419;
    private static final float NUM255 = 255f;
    private static final int NUMFF = 0xff;
    private static final int NUM16 = 16;
    private static final int NUM8 = 8;
    private static final int NUM24 = 24;
    private static final double NUM_5 = 0.5;

    private StatusBarUtil() {
    }

    /**
     * setColor
     *
     * @param ability
     * @param color
     */
    public static void setColor(Ability ability, int color) {
        setColor(ability, color, DEFAULT_STATUS_BAR_ALPHA);
    }

    /**
     * setColor
     *
     * @param activity
     * @param color
     * @param statusBarAlpha
     */
    public static void setColor(Ability activity, int color, int statusBarAlpha) {
        activity.getWindow().setStatusBarColor(calculateStatusColor(color, statusBarAlpha));
    }

    /**
     * setColorForSwipeBack
     *
     * @param activity
     * @param color
     */
    public static void setColorForSwipeBack(Ability activity, int color) {
        setColorForSwipeBack(activity, color, DEFAULT_STATUS_BAR_ALPHA);
    }

    /**
     * setColorForSwipeBack
     *
     * @param activity
     * @param color
     * @param statusBarAlpha
     */
    public static void setColorForSwipeBack(Ability activity, int color, int statusBarAlpha) {
        activity.getWindow().setStatusBarColor(calculateStatusColor(color, statusBarAlpha));
    }

    /**
     * setColorNoTranslucent
     *
     * @param activity
     * @param color
     */
    public static void setColorNoTranslucent(Ability activity, int color) {
        setColor(activity, color, 0);
    }

    /**
     * setColorDiff
     *
     * @param activity
     * @param color
     */
    public static void setColorDiff(Ability activity, int color) {
        transparentStatusBar(activity);
        ComponentContainer contentView = (ComponentContainer) activity.getCurrentFocus();
        Component fakeStatusBarView = contentView.findComponentById(FAKE_STATUS_BAR_VIEW_ID);
        if (fakeStatusBarView != null) {
            if (fakeStatusBarView.getVisibility() == HIDE) {
                fakeStatusBarView.setVisibility(VISIBLE);
            }
            ShapeElement shapeElement = new ShapeElement();
            shapeElement.setRgbColor(fromArgbInt(color));
            fakeStatusBarView.setBackground(shapeElement);
        } else {
            contentView.addComponent(createStatusBarView(activity, color));
        }
    }

    /**
     * setTranslucent
     *
     * @param activity
     */
    public static void setTranslucent(Ability activity) {
        setTranslucent(activity, DEFAULT_STATUS_BAR_ALPHA);
    }

    /**
     * setTranslucent
     *
     * @param activity
     * @param statusBarAlpha
     */
    public static void setTranslucent(Ability activity, int statusBarAlpha) {
        setTransparent(activity);
        addTranslucentView(activity, statusBarAlpha);
    }

    /**
     * setTranslucent
     *
     * @param activity
     * @param statusBarAlpha
     * @param rootLayoutId
     */
    public static void setTranslucent(Ability activity, int statusBarAlpha, int rootLayoutId) {
        setTransparent(activity);
        addTranslucentView(activity, statusBarAlpha, rootLayoutId);
    }

    /**
     * setTranslucentForCoordinatorLayout
     *
     * @param activity
     * @param statusBarAlpha
     */
    public static void setTranslucentForCoordinatorLayout(Ability activity, int statusBarAlpha) {
        transparentStatusBar(activity);
        addTranslucentView(activity, statusBarAlpha);
    }

    /**
     * setTranslucentForCoordinatorLayout
     *
     * @param activity
     * @param statusBarAlpha
     * @param rootLayoutId
     */
    public static void setTranslucentForCoordinatorLayout(Ability activity, int statusBarAlpha, int rootLayoutId) {
        transparentStatusBar(activity);
        addTranslucentView(activity, statusBarAlpha, rootLayoutId);
    }

    /**
     * setTransparent
     *
     * @param activity
     */
    public static void setTransparent(Ability activity) {
        transparentStatusBar(activity);
    }

    /**
     * setTranslucentDiff
     *
     * @param activity
     */
    public static void setTranslucentDiff(Ability activity) {
        activity.getWindow().addFlags(WindowManager.LayoutConfig.MARK_TRANSLUCENT_STATUS);
    }

    /**
     * setColorNoTranslucentForDrawerLayout
     *
     * @param activity
     * @param drawerLayout
     * @param color
     */
    public static void setColorNoTranslucentForDrawerLayout(Ability activity,
                                                            ComponentContainer drawerLayout, int color) {
        setColorForDrawerLayout(activity, drawerLayout, color, 0);
    }

    /**
     * setColorForDrawerLayout
     *
     * @param activity
     * @param drawerLayout
     * @param color
     */
    public static void setColorForDrawerLayout(Ability activity, ComponentContainer drawerLayout, int color) {
        setColorForDrawerLayout(activity, drawerLayout, color, DEFAULT_STATUS_BAR_ALPHA);
    }

    /**
     * setColorForDrawerLayout
     *
     * @param activity
     * @param drawerLayout
     * @param color
     * @param statusBarAlpha
     */
    public static void setColorForDrawerLayout(Ability activity, ComponentContainer drawerLayout, int color,
                                               int statusBarAlpha) {
        if (drawerLayout.findComponentById(FAKE_TRANSLUCENT_VIEW_ID) != null) {
            ShapeElement shapeElement = new ShapeElement();
            color = RgbPalette.parse(DEFAULT_STATUS_BAR_COLOR);
            shapeElement.setRgbColor(fromArgbInt(calculateStatusColor(color, statusBarAlpha)));
            drawerLayout.findComponentById(FAKE_TRANSLUCENT_VIEW_ID).setBackground(shapeElement);
        } else {
            StatusBarUtil.setColor(activity, color, statusBarAlpha);
        }
    }

    private static void setDrawerLayoutProperty(ComponentContainer drawerLayout,
                                                ComponentContainer drawerLayoutContentLayout) {
        drawerLayout.setAutoLayout(false);
        drawerLayoutContentLayout.setAutoLayout(false);
    }

    /**
     * setColorForDrawerLayoutDiff
     *
     * @param activity
     * @param drawerLayout
     * @param color
     */
    public static void setColorForDrawerLayoutDiff(Ability activity, ComponentContainer drawerLayout, int color) {
        activity.getWindow().addFlags(WindowManager.LayoutConfig.MARK_TRANSLUCENT_STATUS);
        ComponentContainer contentLayout = (ComponentContainer) drawerLayout.getComponentAt(0);
        Component fakeStatusBarView = contentLayout.findComponentById(FAKE_STATUS_BAR_VIEW_ID);
        if (fakeStatusBarView != null) {
            if (fakeStatusBarView.getVisibility() == HIDE) {
                fakeStatusBarView.setVisibility(VISIBLE);
            }
            ShapeElement shapeElement = new ShapeElement();
            shapeElement.setRgbColor(fromArgbInt(calculateStatusColor(color, DEFAULT_STATUS_BAR_ALPHA)));
            fakeStatusBarView.setBackground(shapeElement);
        } else {
            contentLayout.addComponent(createStatusBarView(activity, color), 0);
        }
        if (!(contentLayout instanceof DirectionalLayout) && contentLayout.getComponentAt(1) != null) {
            contentLayout.getComponentAt(1).setPadding(0, getStatusBarHeight(activity), 0, 0);
        }
        setDrawerLayoutProperty(drawerLayout, contentLayout);
    }

    /**
     * setTranslucentForDrawerLayout
     *
     * @param activity
     * @param drawerLayout
     */
    public static void setTranslucentForDrawerLayout(Ability activity, ComponentContainer drawerLayout) {
        setTranslucentForDrawerLayout(activity, drawerLayout, DEFAULT_STATUS_BAR_ALPHA);
    }

    /**
     * setTranslucentForDrawerLayout
     *
     * @param activity
     * @param drawerLayout
     * @param statusBarAlpha
     */
    public static void setTranslucentForDrawerLayout(Ability activity, ComponentContainer drawerLayout,
                                                     int statusBarAlpha) {
        setTransparentForDrawerLayout(activity, drawerLayout);
        addTranslucentView(activity, statusBarAlpha);
    }

    /**
     * setTranslucentForDrawerLayout
     *
     * @param activity
     * @param drawerLayout
     * @param statusBarAlpha
     * @param layoutid
     */
    public static void setTranslucentForDrawerLayout(Ability activity, ComponentContainer drawerLayout,
                                                     int statusBarAlpha, int layoutid) {
        setTransparentForDrawerLayout(activity, drawerLayout);
        addTranslucentView(activity, statusBarAlpha, layoutid);
    }

    /**
     * setTransparentForDrawerLayout
     *
     * @param activity
     * @param drawerLayout
     */
    public static void setTransparentForDrawerLayout(Ability activity, ComponentContainer drawerLayout) {
        activity.getWindow().addFlags(WindowManager.LayoutConfig.MARK_TRANSLUCENT_STATUS);
    }

    /**
     * setTransparentForImageView
     *
     * @param activity
     * @param rootLayoutId
     */
    public static void setTransparentForImageView(Ability activity, int rootLayoutId) {
        addTranslucentView(activity, DEFAULT_STATUS_BAR_ALPHA, rootLayoutId);
    }

    /**
     * setTranslucentForImageView
     *
     * @param activity
     * @param needOffsetView
     * @param rootLayoutId
     */
    public static void setTranslucentForImageView(Ability activity, Component needOffsetView, int rootLayoutId) {
        setTranslucentForImageView(activity, DEFAULT_STATUS_BAR_ALPHA, needOffsetView, rootLayoutId);
    }

    /**
     * setTranslucentForImageView
     *
     * @param activity
     * @param statusBarAlpha
     * @param needOffsetView
     * @param rootLayoutId
     */
    public static void setTranslucentForImageView(Ability activity, int statusBarAlpha,
                                                  Component needOffsetView, int rootLayoutId) {
        setTransparentForWindow(activity);
        addTranslucentView(activity, statusBarAlpha, rootLayoutId);
    }

    /**
     * setTransparentForImageViewInFragment
     *
     * @param activity
     * @param needOffsetView
     */
    public static void setTransparentForImageViewInFragment(Ability activity, Component needOffsetView) {
        setTranslucentForImageViewInFragment(activity, 0, needOffsetView);
    }

    /**
     * setTranslucentForImageViewInFragment
     *
     * @param activity
     * @param needOffsetView
     */
    public static void setTranslucentForImageViewInFragment(Ability activity, Component needOffsetView) {
        setTranslucentForImageViewInFragment(activity, DEFAULT_STATUS_BAR_ALPHA, needOffsetView);
    }

    /**
     * setTranslucentForImageViewInFragment
     *
     * @param activity
     * @param statusBarAlpha
     * @param needOffsetView
     */
    public static void setTranslucentForImageViewInFragment(Ability activity, int statusBarAlpha,
                                                            Component needOffsetView) {
        clearPreviousSetting(activity);
    }

    /**
     * hideFakeStatusBarView
     *
     * @param activity
     */
    public static void hideFakeStatusBarView(Ability activity) {
        ComponentContainer decorView = (ComponentContainer) activity.getCurrentFocus();
        Component fakeStatusBarView = decorView.findComponentById(FAKE_STATUS_BAR_VIEW_ID);
        if (fakeStatusBarView != null) {
            fakeStatusBarView.setVisibility(HIDE);
        }
        Component fakeTranslucentView = decorView.findComponentById(FAKE_TRANSLUCENT_VIEW_ID);
        if (fakeTranslucentView != null) {
            fakeTranslucentView.setVisibility(HIDE);
        }
    }

    /**
     * setLightMode
     *
     * @param activity
     */
    public static void setLightMode(Ability activity) {
        setMIUIStatusBarDarkIcon(activity, true);
        setMeizuStatusBarDarkIcon(activity, true);
        activity.getWindow().addFlags(MARK_TRANSLUCENT_STATUS);
    }

    /**
     * setDarkMode
     *
     * @param activity
     */
    public static void setDarkMode(Ability activity) {
        setMIUIStatusBarDarkIcon(activity, false);
        setMeizuStatusBarDarkIcon(activity, false);
        activity.getWindow().addFlags(MARK_TRANSLUCENT_STATUS);
    }

    private static void setMIUIStatusBarDarkIcon(Ability activity, boolean isDarkIcon) {
        return;
    }

    private static void setMeizuStatusBarDarkIcon(Ability activity, boolean isDarkIcon) {
        try {
            WindowManager.LayoutConfig lp = activity.getWindow().getLayoutConfig().get();
            Field darkFlag = WindowManager.LayoutConfig.class.getDeclaredField("MEIZU_FLAG_DARK_STATUS_BAR_ICON");
            Field meizuFlags = WindowManager.LayoutConfig.class.getDeclaredField("meizuFlags");
            int bit = darkFlag.getInt(null);
            int value = meizuFlags.getInt(lp);
            if (isDarkIcon) {
                value |= bit;
            } else {
                value &= ~bit;
            }
            meizuFlags.setInt(lp, value);
            activity.getWindow().setLayoutConfig(lp);
        } catch (IllegalArgumentException | IllegalAccessException | NoSuchFieldException e) {
            e.getMessage();
        }
    }

    private static void clearPreviousSetting(Ability activity) {
        ComponentContainer decorView = (ComponentContainer) activity.getCurrentFocus();
        Component fakeStatusBarView = decorView.findComponentById(FAKE_STATUS_BAR_VIEW_ID);
        if (fakeStatusBarView != null) {
            decorView.removeComponent(fakeStatusBarView);
            decorView.setPadding(0, 0, 0, 0);
        }
    }

    private static void addTranslucentView(Ability activity, int statusBarAlpha) {
        ComponentContainer contentView = (ComponentContainer) activity.getCurrentFocus();
        if (contentView.findComponentById(FAKE_TRANSLUCENT_VIEW_ID) != null) {
            Component fakeTranslucentView = contentView.findComponentById(FAKE_TRANSLUCENT_VIEW_ID);
            if (fakeTranslucentView.getVisibility() == HIDE) {
                fakeTranslucentView.setVisibility(VISIBLE);
            }
            ShapeElement shapeElement = new ShapeElement();
            shapeElement.setRgbColor(new RgbColor(0, 0, 0, statusBarAlpha));
            fakeTranslucentView.setBackground(shapeElement);
        } else {
            contentView.addComponent(createTranslucentStatusBarView(activity, statusBarAlpha));
        }
    }

    private static void addTranslucentView(Ability activity, int statusBarAlpha, int layoutid) {
        ComponentContainer contentView = (ComponentContainer) activity.findComponentById(layoutid);
        if (contentView.findComponentById(FAKE_TRANSLUCENT_VIEW_ID) != null) {
            Component fakeTranslucentView = contentView.findComponentById(FAKE_TRANSLUCENT_VIEW_ID);
            if (fakeTranslucentView.getVisibility() == HIDE) {
                fakeTranslucentView.setVisibility(VISIBLE);
            }
            ShapeElement shapeElement = new ShapeElement();
            shapeElement.setRgbColor(new RgbColor(0, 0, 0, statusBarAlpha));
            fakeTranslucentView.setBackground(shapeElement);
        } else {
            if (contentView instanceof DirectionalLayout) {
                contentView.addComponent(createTranslucentStatusBarView(activity, statusBarAlpha), 0);
            } else {
                contentView.addComponent(createTranslucentStatusBarView(activity, statusBarAlpha));
            }
        }
    }

    private static Component createStatusBarView(Ability activity, int color) {
        return createStatusBarView(activity, color, 0);
    }

    private static Component createStatusBarView(Ability activity, int color, int alpha) {
        Component statusBarView = new Component(activity);
        statusBarView.setWidth(DirectionalLayout.LayoutConfig.MATCH_PARENT);
        statusBarView.setHeight(getStatusBarHeight(activity));
        ShapeElement shapeElement = new ShapeElement();
        shapeElement.setRgbColor(fromArgbInt(calculateStatusColor(color, alpha)));
        statusBarView.setBackground(shapeElement);
        statusBarView.setId(FAKE_STATUS_BAR_VIEW_ID);
        return statusBarView;
    }

    private static void setTransparentForWindow(Ability activity) {
        activity.getWindow().addFlags(MARK_TRANSLUCENT_STATUS);
    }

    private static void transparentStatusBar(Ability activity) {
        activity.getWindow().addFlags(WindowManager.LayoutConfig.MARK_DRAWS_SYSTEM_BAR_BACKGROUNDS);
        activity.getWindow().clearFlags(WindowManager.LayoutConfig.MARK_TRANSLUCENT_STATUS);
        activity.getWindow().addFlags(WindowManager.LayoutConfig.MARK_TRANSLUCENT_NAVIGATION);
        activity.getWindow().setStatusBarColor(Color.TRANSPARENT.getValue());
    }

    private static Component createTranslucentStatusBarView(Ability activity, int alpha) {
        Component statusBarView = new Component(activity);
        statusBarView.setWidth(DirectionalLayout.LayoutConfig.MATCH_PARENT);
        statusBarView.setHeight(getStatusBarHeight(activity));
        ShapeElement shapeElement = new ShapeElement();
        shapeElement.setRgbColor(new RgbColor(0, 0, 0, alpha));
        statusBarView.setBackground(shapeElement);
        statusBarView.setId(FAKE_TRANSLUCENT_VIEW_ID);
        return statusBarView;
    }

    /**
     * getStatusBarHeight
     *
     * @param context
     * @return int
     */
    public static int getStatusBarHeight(Context context) {
        return DEFAULT_STATUS_BAR_HIGHT;
    }

    /**
     * calculateStatusColor
     *
     * @param color
     * @param alpha
     * @return int
     */
    public static int calculateStatusColor(int color, int alpha) {
        if (alpha == 0) {
            return color;
        }
        float a1 = 1 - alpha / NUM255;
        int red = color >> NUM16 & NUMFF;
        int green = color >> NUM8 & NUMFF;
        int blue = color & NUMFF;
        red = (int) (red * a1 + NUM_5);
        green = (int) (green * a1 + NUM_5);
        blue = (int) (blue * a1 + NUM_5);
        return (NUMFF << NUM24) | (red << NUM16) | (green << NUM8) | blue;
    }
}
